﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace EvolutionWin
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void CreateField()
        {
            int i, j;
            clearField();
            fSize = (int)this.evoSize.Value;
           

            int cellWidth = this.evoField.Size.Width / fSize;
            int cellHeight = this.evoField.Size.Height/ fSize;


            field = new System.Windows.Forms.PictureBox[fSize, fSize];

            for (i = 0; i < fSize; i++)
            {
                for (j = 0; j < fSize; j++)
                {
                    field[i,j] = new System.Windows.Forms.PictureBox();
                    this.evoField.Controls.Add(field[i,j]);

                    field[i, j].Name = "fbox_"+ i.ToString() + "_"+ j.ToString();
                    
                    field[i, j].BackColor = System.Drawing.SystemColors.GradientActiveCaption;

                    field[i, j].Size = new System.Drawing.Size(cellWidth,cellHeight);

                    field[i, j].Location = new System.Drawing.Point(j * cellWidth, i * cellHeight);

                    field[i, j].BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;

                    field[i, j].TabIndex = 0;
                    
                    field[i, j].TabStop = false;

                    field[i, j].Tag = 0;

                    field[i, j].Click += new System.EventHandler(this.fieldCell_Click);
            
                }
            }

            
            if (fillRandomly.Checked)
            {
                fillCellsRand((int)rndNum.Value);
            }

        
        }



        private void btnStart_Click(object sender, EventArgs e)
        {

            CreateField();

        }


        #region Field Painting

        //to fill the field randomly according to the paramenter
        private void fillCellsRand(int num)
        {

            Random rnd = new Random(DateTime.Now.Millisecond);

            for (int i = 0; i < fSize; i++)
            {
                for (int j = 0; j < fSize; j++)
                {
                    field[i, j].Tag = (rnd.Next(1, 101) % num == 0) ? 1 : 0;
                    repaintCell(field[i, j]);
                }
            }
    

        }
        
        
        private void repaintCell(System.Windows.Forms.PictureBox pb)
        {
            if ((int)(pb.Tag) == 0)
            {
                pb.BackColor = System.Drawing.SystemColors.GradientActiveCaption;
            }
            else 
            {
                pb.BackColor = System.Drawing.Color.Green;
            }
        
        }

        private void fieldCell_Click(object sender, EventArgs e)
        {
            ((System.Windows.Forms.PictureBox)sender).Tag = ((int)(((System.Windows.Forms.PictureBox)sender).Tag) + 1) % 2;
            repaintCell((System.Windows.Forms.PictureBox)sender);


        }

        #endregion



        #region Manage params
      
        
        private void birthNum_ValueChanged(object sender, EventArgs e)
        {
            if (birthNum.Value > deathNum.Value)
            {
                deathNum.Value = birthNum.Value;
            }

        }

        private void deathNum_ValueChanged(object sender, EventArgs e)
        {
            if (birthNum.Value > deathNum.Value)
            {
               birthNum.Value =  deathNum.Value ;
            }
        }


        private void fillManually_CheckedChanged(object sender, EventArgs e)
        {
            if (fillManually.Checked)
            {
                rndNum.Enabled = false;
            }
            else
            {
                rndNum.Enabled = true;
            }
        }


        private void runByTimer_CheckedChanged(object sender, EventArgs e)
        {
            if (tmrManaged.Checked)
            {
                tmrInterval.Enabled = true;
                btnRecalculate.Text = "Evluate automatically";
            }
            else
            {
                tmrInterval.Enabled = false;
                StepTimer.Enabled = false;
                EnableDisableControls(true);
                btnRecalculate.Text = "Evluate manually";
            }
        }
        #endregion

       
        
        
        
        
        
        #region Recalculate matrix
        
        
        private int isExist(int n, int m)
        {
            return ((n >= 0 && m >= 0 && n < fSize && m < fSize) ? (int)field[n, m].Tag : 0);
        }

        //it is simple. The function returns the number of the cell's neigbours.
        private int numOfNeighbors(int n, int m)
        {
            //we are on the firs or the last line of matrix
            if ((n - 1) < 0 || n + 1 == fSize)
            {
                if (m == 0 || m == fSize - 1)
                {
                    return 3;
                }
                else
                {
                    return 5;
                }
            }
            //we are on the first or the last column of matrix
            if (m - 1 < 0 || m + 1 == fSize)
            {
                return 5;
            }

            return 8;
        }


        //function to recalculate the next evolution step.
        public void Recalculate()
        {
            int i, j;
            int tmp;

            int[,] tmp_arr = new int[fSize, fSize];

            for (i = 0; i < fSize; i++)
            {
                for (j = 0; j < fSize; j++)
                {
                    tmp = isExist(i - 1, j - 1) + isExist(i - 1, j) + isExist(i - 1, j + 1) +
                          isExist(i,     j - 1) +                     isExist(i,     j + 1) +
                          isExist(i + 1, j - 1) + isExist(i + 1, j) + isExist(i + 1, j + 1);

                    //if the cell is zero and it has at least 2 1-value neigbours set it to 1 value, otherwise it has to be set to zero.
                    if ((int)field[i, j].Tag == 0)
                    {
                        if (tmp >= (int)birthNum.Value)
                        {
                            tmp_arr[i, j] = 1;
                        }
                        else
                        {
                            tmp_arr[i, j] = 0;
                        }

                    }
                    else
                    {
                        //if the cell is 1value and it has only 1-value cells around it set it to zero
                        if ((closelyBox.Checked && tmp == numOfNeighbors(i, j)) || tmp >= (int)deathNum.Value)
                        {
                            tmp_arr[i, j] = 0;
                        }
                        else
                        {
                            tmp_arr[i, j] = 1;
                        }
                    }

                }

            }


            for (i = 0; i < fSize; i++)
            {
                for (j = 0; j < fSize; j++)
                { 
                    field[i,j].Tag = tmp_arr[i,j];
                    repaintCell(field[i, j]);
                }
            }

        


    }

        #endregion

        private void btnRecalculate_Click(object sender, EventArgs e)
        {
            if (tmrManaged.Checked)
            {
                if (StepTimer.Enabled = !StepTimer.Enabled)
                {
                    btnRecalculate.Text = "Stop evaluate";
                    EnableDisableControls(false);
                }
                else
                {
                    btnRecalculate.Text = "Evaluate automatically";
                    EnableDisableControls(true);
                }
                return;
            }

            Recalculate();

        }

        private void StepTimer_Tick(object sender, EventArgs e)
        {
            Recalculate();
        }

        private void tmrInterval_ValueChanged(object sender, EventArgs e)
        {
            StepTimer.Interval = (int)tmrInterval.Value;
        }

        private void EnableDisableControls(bool fl)
        {
            if (fl)
            {
                evoSize.Enabled = true;
                fillRandomly.Enabled = true;
                fillManually.Enabled = true;
                btnStart.Enabled = true;
                rndNum.Enabled = true;
            }
            else 
            {

                evoSize.Enabled = false;
                fillRandomly.Enabled = false;
                fillManually.Enabled = false;
                btnStart.Enabled = false;
                rndNum.Enabled = false;
            }
        }

    }
}
